package com.tzm.netty.http;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class TestServer {
    public static void main(String[] args) throws InterruptedException {
        /*实例化主Reactor线程组：bossGroup，
            1.负责处理TCP/IP的连接，初始化Channel参数
            2.将链路状态变更时间通知给ChannelPipeLine
        */
        EventLoopGroup bossGroup=new NioEventLoopGroup(1);
        /*
         实例化从Reactor:workerGroup 用于处理IO相关的读写操作，或者执行系统task，定时任务task等
             1.异步读取通信对端的数据报，发送读事件到ChannelPipeLine
             2.异步发送消息到通信对端，调用ChannelPipeline的消息到发送接口；
             3.执行系统调用task
             4.执行定时任务task，例如链路空闲状态检测
         */
        EventLoopGroup workerGroup=new NioEventLoopGroup();//最大线程数量。如果指定为0或不写，那么Netty会将线程数量设置为CPU逻辑处理器数量的2倍

        try{
            //启动配置类，ServerBootstrap是服务端启动配置类，bootStrap是netty客户端启动配置类
            ServerBootstrap serverBootstrap=new ServerBootstrap();
            /*
                1.group(bossGroup, workerGroup) 绑定线程组，设置reactor模式的主线程以及IO操作池
                2.channel(Class<? extends C> channelClass) 设置通讯模式 服务端一般选NioServerSocketChannel，客户端一般选NioSocketChannel。
                3.handler 设置主通道的处理器
                    .childHandler()；只有服务端ServerBootstrap才有child类型的方法
                    对于服务端而言有两种通道需要处理，一种是ServerSocketChannel：由于处理和用户连接的accept操作
                    另一种是SocketChannel表示对应客户端的连接
                    而对于客户端，一般都只有一种channel，也就是SocketChannel。
               因此以child开头的方法，都定义在ServerBootstrap中，表示处理或配置服务端接收到的对应客户端连接的SocketChannel通道。
             */
            serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(new TestServerInitializer());
            /*绑定一个端口并且同步, 生成了一个 ChannelFuture 对象
                因为这里netty不仅是绑定端口，更是建立连接（内部封装） server.accpet()这个是阻塞的，所以设置成异步
            */
            ChannelFuture channelFuture=serverBootstrap.bind(6668).sync();
            /*closeFuture()是开启了一个子线程server channel监听器，负责监听channel是否关闭的状态
                channel.close()才是主动关闭通道的方法。
            */
            channelFuture.channel().closeFuture().syncUninterruptibly();

        }finally{
            //优雅地关闭线程组
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
